<script setup>
import { ControlButton, Controls } from '@vue-flow/controls'
import { MarkerType, Position, VueFlow, useVueFlow } from '@vue-flow/core'
import { MiniMap } from '@vue-flow/minimap'
import { ref } from 'vue'
import DropzoneBackground from './DropzoneBackground.vue'
import Icon from './Icon.vue'
// import { initialEdges, initialNodes } from './initial-elements.js'
import useDragAndDrop from './useDnD'

import InteractionControls from './InteractionControls.vue'
import Sidebar from './Sidebar.vue'
import SaveRestoreControls from './SaveRestoreControls.vue'
import TransitionEdge from './TransitionEdge.vue'

import ColorSelectorNode from './nodes/ColorSelectorNode.vue'
import OutputNode from './nodes/OutputNode.vue'
import { presets } from './nodes/presets.js'

/**
 * useVueFlow provides all event handlers and store properties
 * You can pass the composable an object that has the same properties as the VueFlow component props
 */
const { onPaneReady, onNodeDrag, onNodeDragStop, getIntersectingNodes, isNodeIntersecting, updateNode, onConnect, addEdges, setViewport, toObject } = useVueFlow()

const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop()

const initialNodes = [
  { id: '1', type: 'input', label: 'Node 1', position: { x: 250, y: 0 }, class: 'light' },
  { id: '2', label: 'Node 2', position: { x: 100, y: 100 }, class: 'light',targetPosition: Position.Top, },
  { id: '3', label: 'Node 3', position: { x: 400, y: 100 }, class: 'light' },
  { id: '4', label: 'Node 4', position: { x: 150, y: 200 }, class: 'light' },
  { id: '5', label: 'Node 5', position: { x: 300, y: 300 }, class: 'light' },
  {
    id: '11',
    type: 'input',
    label: '双击我',
    position: { x: 0, y: 30 },
    sourcePosition: Position.Right,
  },
  {
    id: '12',
    // type: 'output',
    label: '双击我',
    position: { x: 1000, y: 800 },
    targetPosition: Position.Left,
  },
  {
    id: '21',
    type: 'color-selector',
    data: { color: presets.ayame },
    position: { x: 0, y: 450},
  },
  {
    id: '22',
    type: 'output',
    position: { x: 350, y: 450 },
    targetPosition: Position.Left,
  },
]

const initialEdges = [
  { id: 'e1-2', source: '1', target: '2', animated: true },
  { id: 'e1-3', label: 'edge with arrowhead', source: '1', animated: true, target: '3', markerEnd: MarkerType.ArrowClosed },
  {
    id: 'e4-5',
    type: 'step',
    label: 'step-edge',
    source: '4',
    target: '5',
    animated: true, 
    style: { stroke: 'orange' },
    labelBgStyle: { fill: 'orange' },
  },
  { id: 'e3-4', type: 'smoothstep', label: 'smoothstep-edge', source: '3', target: '4',animated: true },
  { id: 'e11-2', type: 'custom', source: '11', target: '12', animated: true, style: () => ({
      stroke: colorSelectorData.value?.color,
    }), },
  {
    id: 'e1a-2',
    source: '21',
    sourceHandle: 'a',
    target: '22',
    animated: true,
    style: () => ({
      stroke: colorSelectorData.value?.color,
    }),
  },
]


const nodes = ref(initialNodes)

const colorSelectorData = toRef(() => nodes.value[0].data)

const edges = ref(initialEdges)

// our dark mode toggle flag
const dark = ref(false)

/**
 * This is a Vue Flow event-hook which can be listened to from anywhere you call the composable, instead of only on the main component
 * Any event that is available as `@event-name` on the VueFlow component is also available as `onEventName` on the composable and vice versa
 *
 * onPaneReady is called when viewpane & nodes have visible dimensions
 */
onPaneReady(({ fitView }) => {
  fitView()
  // fitView({ nodes: ['11'] })
})

onNodeDrag(({ event, node, intersections }) => {
  const intersectionIds = intersections.map((intersection) => intersection.id)
  console.log('event',event)
  console.log('nodes',nodes.value)
  console.log('node',node)
  console.log('intersections',intersectionIds)
  for (const node of nodes.value) {
    const isIntersecting = intersectionIds.includes(node.id)

    updateNode(node.id, { class: isIntersecting ? 'intersecting' : '' })
  }
})

/**
 * onNodeDragStop is called when a node is done being dragged
 *
 * Node drag events provide you with:
 * 1. the event object
 * 2. the nodes array (if multiple nodes are dragged)
 * 3. the node that initiated the drag
 * 4. any intersections with other nodes
 */
onNodeDragStop(({ event, nodes, node, intersections }) => {
  console.log('Node Drag Stop', { event, nodes, node, intersections })
})

/**
 * onConnect is called when a new connection is created.
 *
 * You can add additional properties to your new edge (like a type or label) or block the creation altogether by not calling `addEdges`
 */
onConnect((connection) => {
  addEdges(connection)
})

/**
 * To update a node or multiple nodes, you can
 * 1. Mutate the node objects *if* you're using `v-model`
 * 2. Use the `updateNode` method (from `useVueFlow`) to update the node(s)
 * 3. Create a new array of nodes and pass it to the `nodes` ref
 */
function updatePos() {
  nodes.value = nodes.value.map((node) => {
    return {
      ...node,
      position: {
        x: Math.random() * 400,
        y: Math.random() * 400,
      },
    }
  })
}

/**
 * toObject transforms your current graph data to an easily persist-able object
 */
function logToObject() {
  console.log(toObject())
}

/**
 * Resets the current viewport transformation (zoom & pan)
 */
function resetTransform() {
  setViewport({ x: 0, y: 0, zoom: 1 })
}

function toggleDarkMode() {
  dark.value = !dark.value
}


// minimap stroke color functions
function nodeStroke(n) {
  switch (n.type) {
    case 'input':
      return '#000'
    case 'color-selector':
      return presets.sumi
    case 'output':
      return '#ff0072'
    default:
      return '#000'
  }
}

function nodeColor(n) {
  if (n.type === 'color-selector') {
    return colorSelectorData.value?.color
  }

  return '#000'
}
</script>

<template>
  <div class="dndflow" @drop="onDrop">
      <!-- <Bar /> -->
      <Sidebar />

      <VueFlow
        @dragover="onDragOver" 
        @dragleave="onDragLeave"
        :nodes="nodes"
        :edges="edges"
        class="basicflow interactionflow  custom-node-flow"

        :class="[colorSelectorData?.isGradient ? 'animated-bg-gradient' : dark]"
        :style="{ backgroundColor: colorSelectorData?.color }"

        :default-viewport="{ zoom: 1.5 }"
        :min-zoom="0.2"
        :max-zoom="4"
        fit-view-on-init
      >
        <!-- <Background pattern-color="#aaa" :gap="16" /> -->

        <DropzoneBackground
          :style="{
            backgroundColor: isDragOver ? '#e7f3ff' : 'transparent',
            transition: 'background-color 0.2s ease',
          }"
        />

        <template #edge-custom="props">
          <TransitionEdge v-bind="props" />
        </template>

        <template #node-color-selector="{ id }">
          <ColorSelectorNode :id="id" />
        </template>

        <template #node-output>
          <OutputNode />
        </template>

        <InteractionControls />

        <SaveRestoreControls />

        <!-- <MiniMap /> -->
        <MiniMap :node-stroke-color="nodeStroke" :node-color="nodeColor" />

        <Controls position="top-right">
          <ControlButton title="Reset Transform" @click="resetTransform">
            <Icon name="reset" />
          </ControlButton>

          <ControlButton title="Shuffle Node Positions" @click="updatePos">
            <Icon name="update" />
          </ControlButton>

          <ControlButton title="Toggle Dark Mode" @click="toggleDarkMode">
            <Icon v-if="dark" name="sun" />
            <Icon v-else name="moon" />
          </ControlButton>

          <ControlButton title="Log `toObject`" @click="logToObject">
            <Icon name="log" />
          </ControlButton>
        </Controls>
      </VueFlow>
    </div>

  
</template>

<style scoped>
@import "./VueFlow.css";
</style>

<style>
/* 碰撞样式 */
.vue-flow__node.intersecting{
  background-color:#ff0 !important
}

</style>
